<%
'######################################################################
'## App.TagLib.asp
'## -------------------------------------------------------------------
'## Feature     :   AppCore TagCms
'## Version     :   v1.0.0
'## Author      :   Lajox (lajox@19www.com)
'## Update Date :   2015/11/10 13:12
'## HomePage	:   http://www.19www.com
'## -------------------------------------------------------------------
'## Description :   AppCore Cms标签解析
'######################################################################

Class Cls_App_TagCms

	Private s_dictName, s_tbPrefix
	Private b_debug, b_extend
	Private o_db, o_ds, o_pager
	Private a_condi

	Private Sub Class_Initialize()
		On Error Resume Next
		b_debug = App.Debug
		b_extend = True '是否支持拓展参数
		Set o_ds = AB.C.Dict()
		Set o_pager = AB.C.Dict()
		s_tbPrefix = App.Dao.tbPrefix '数据表前缀
		Set o_db = App.Dao.db() '数据库驱动托管于App.Dao.db
		AB.Use "E" : AB.E.Use "Md5"
		AB.Use "A"
		On Error GoTo 0
	End Sub

	Private Sub Class_Terminate()
		Set o_ds = Nothing
		Set o_pager = Nothing
	End Sub

	Public Function Parse(ByVal str)
		On Error Resume Next
		str = ParseCmsTag(str)
		str = ParseSysTag(str)
		Parse = str
		On Error GoTo 0
	End Function
	
	Public Function ParseCmsTag(ByVal str)
		On Error Resume Next
		Dim RegEx, Match, RegExTmp, MatchTmp, RegAttrs, attr, rule, rule_asp, mark, attrs, tmp, k, arr, table, prefix, fields, a_extend, s_extend, rs
		Dim sql, pk, var, md5, cvar, cval, inner
		Dim hasData, hasConn, hasPageSize : hasPageSize = False
		a_condi = Array("sql","table","prefix","loop","rows","num","offset","pagesize","pagemark","order","return","data","conn") '主要筛选参数
		rule_asp = "\<"&"%=(.+)%"&"\>" 
		If AB.C.RegTest(str, rule_asp) Then '用于嵌套
			Set RegExTmp = AB.C.RegMatch(str, rule_asp)
			For Each MatchTmp In RegExTmp
				tmp = MatchTmp.SubMatches(0)
				tmp = AB.C.RP( tmp, Array("'",""""), Array(Chr(15),Chr(16)) )
				str = AB.C.RP( str, MatchTmp.Value, "<"&"%="& tmp &"%"&">")
			Next
		End If
		Set RegExTmp = Nothing
		'rule = "{cmstag:([\S]+)\s+([\s\S]*?)}([\s\S]*?){/cmstag:\1}" '通用智能标签
		rule = "{cmstag:([\w\-]+)\s*([\s\S]*?)}([\s\S]*?){/cmstag:\1}" '通用智能标签
		Set RegEx = AB.C.RegMatch(str, rule)
		For Each Match In RegEx
			o_ds.RemoveAll
			mark = Match.SubMatches(0)
			attrs = Match.SubMatches(1) '各项属性
			inner = Match.SubMatches(2)
			o_ds("table") = mark
			a_extend = Array() : s_extend = ""
			Set RegAttrs = AB.C.RegMatch(attrs,"([a-zA-Z0-9_]+)=(['""]?)([^'""\s]*|[^\2]*?)\2")
			For Each attr In RegAttrs
				cvar = Trim(attr.SubMatches(0))
				cval = attr.SubMatches(2)
				cval = AB.C.RP( cval, Array("\\","\@","\#","\$"), Array(Chr(17),Chr(18),Chr(19),Chr(20)) )
				cval = AB.C.RegReplace( cval, "\(\$([\w]+)\)", """& $1 &""" ) '替换变量
				cval = AB.C.RegReplace( cval, "<"&"%=(.+)%"&">", """& $1 &""" ) '替换变量
				cval = AB.C.RP( cval, Array(Chr(15),Chr(16)), Array("'","""") ) '用于嵌套
				Select Case LCase(cvar)
					Case "sql"
						If Trim(cval)<>"" Then
							o_ds("sql") = Trim(cval)
						End If
					Case "table"
						If Trim(cval)<>"" Then
							o_ds("table") = Trim(cval)
						End If
					Case "loop","rows","num"
						If AB.C.IsNum(cval) Then o_ds("rows")=CLng(cval) Else o_ds("rows")=0
					Case "offset"
						If AB.C.IsNum(cval) Then o_ds("offset")=CLng(cval) Else o_ds("offset")=0
					Case "pagesize" '设置分页数
						hasPageSize = True
						o_ds("pagesize") = Trim(cval)
						If AB.C.IsNum(Trim(cval)) Then
							o_pager("size") = CLng(Trim(cval))
							If o_pager("size")<=0 Then o_pager("size") = CLng(App.View.PageSize)
						Else
							o_pager("size") = CLng(App.View.PageSize)
						End If
					Case "pagemark" '分页标识
						hasPageSize = True
						o_pager("mark") = Trim(cval)
						If Trim(o_pager("mark"))="" Then o_pager("mark") = App.View.PageMark
					Case Else
						o_ds(LCase(cvar)) = cval
				End Select
			Next
			prefix = AB.C.IIF(o_ds.Exists("prefix"), o_ds("prefix"), s_tbPrefix) '数据表前缀
			If Trim(o_ds("sql"))<>"" Then
				sql = o_ds("sql")
			Else
				pk = App.Dao.T(Trim(o_ds("table"))).getPk() '主键字段
				If Trim(o_ds("order"))="" Then
					If Not AB.C.IsNul(pk) Then o_ds("order") = pk & " desc"
				Else
					tmp = Trim(o_ds("order"))
					arr = Array()
					For Each k In Split(tmp,",")
						If InStr(LCase(k)," desc")<=0 And InStr(LCase(k)," asc")<=0 Then
							k = k & " desc"
						End If
						arr = AB.A.Push(arr, k)
					Next
					o_ds("order") = Join(arr, ", ")
				End If
				If b_extend Then '支持拓展参数
					table = Trim(o_ds("table"))
					''fields = App.Dao.T(table).tbFields()
					''Set rs = App.Dao.T(table).Top(1).Result()
					Set rs = App.Dao.Query("SELECT top 1 * FROM " & prefix & table )
					fields = App.Dao.RsFields(rs)
					For Each k In o_ds
						If Not AB.A.InArray(k,a_condi) Then
							If AB.A.InArray(k,fields) Then
								If Not AB.C.IsNum(o_ds(k)) Then
									a_extend = AB.A.Push(a_extend, k& "='"& o_ds(k) & "'")
								Else
									If AB.A.InArray(rs.Fields(k).Type, Array(129,130,201,202,203)) Then '字符串类型
										a_extend = AB.A.Push(a_extend, k& "='"& o_ds(k) & "'")
									Else
										a_extend = AB.A.Push(a_extend, k& "="& o_ds(k))
									End If
								End If
							End If
						End If
					Next
					rs.Close() : Set rs = Nothing
					s_extend = Join(a_extend, " AND ")
				End If
				sql = "SELECT "& AB.C.IIF(Trim(o_ds("field"))="","*",Trim(o_ds("field"))) &" FROM " & ( prefix & Trim(o_ds("table")) ) &_
					" WHERE 1=1 " & AB.C.IIF(Trim(o_ds("where"))="",""," AND " & o_ds("where")) &_
					"" & AB.C.IIF(Trim(s_extend)="",""," AND " & s_extend) &_
					"" & AB.C.IIF(Trim(o_ds("order"))="",""," ORDER BY " & o_ds("order"))
			End If
			sql = AB.C.RP(sql, "#@", prefix)
			sql = AB.C.RP(sql, Array(Chr(17),Chr(18),Chr(19),Chr(20)), Array("\","@","#","$"))
			If AB.C.RegTest(sql, rule_asp) Then '用于嵌套
				Set RegExTmp = AB.C.RegMatch(sql, rule_asp)
				For Each MatchTmp In RegExTmp
					tmp = MatchTmp.SubMatches(0)
					tmp = AB.C.RP( tmp, Array(Chr(15),Chr(16)), Array("'","""") ) '用于嵌套
					sql = AB.C.RP( sql, MatchTmp.Value, """ & "& tmp &" & """)
				Next
			End If
			Set RegExTmp = Nothing
			o_pager("sql") = Trim(sql) '记录分页sql语句
			md5 = LCase(AB.E.Md5.To8(Now()& AB.C.Rand(10000,99999)))
			var = mark & "_" & md5
			If Trim(o_ds("return"))<>"" Then var = Trim(o_ds("return")) '用return值作标识符
			o_pager("offset") = AB.C.IIF(CLng(o_ds("offset"))<0,0,CLng(o_ds("offset"))) '偏移量
			o_pager("rows") = AB.C.IIF(CLng(o_ds("rows"))<0,0,CLng(o_ds("rows"))) '取数量
			hasData = False
			If Trim(o_ds("data"))<>"" Then '直接传递data参数
				o_ds("data") = AB.C.RegReplace( o_ds("data"), "(['""])([^\1]*?)\1", """$2""" )
				o_ds("data") = Trim(o_ds("data"))
				hasData = True
			End If
			hasConn = False
			If Trim(o_ds("conn"))<>"" Then '带conn参数
				o_ds("conn") = AB.C.RegReplace( o_ds("conn"), "(['""])([^\1]*?)\1", """$2""" )
				o_ds("conn") = Trim(o_ds("conn"))
				hasConn = True
			End If
			If hasPageSize Then '有设置分页
				o_pager("set") = var '传递分页设置
				o_pager("mark") = AB.C.IfHas(Trim(o_pager("mark")), "p") '分页标识符
				o_pager("size") = AB.C.IfHas(CLng(o_pager("size")), CLng(App.View.PageSize)) '每页数量
				o_pager("no") = CLng(App.Req( o_pager("mark") )) '当前页码
				If o_pager("no")<=0 Then o_pager("no") = 1
				'--
				If o_pager("no")<=0 Then o_pager("no") = 1
				str = AB.C.RP( str, Match.Value, "<"&"% Dim i_"&md5&", PageCount_"&md5&" "& VBCrlf &" " &_
						" AB.C.Dim("""& var &""") : AB.C.Dim(""conn_"& md5 &""") "& VBCrlf &" " &_
						AB.C.IIF(hasConn, " If AB.C.IsConn("& o_ds("conn") &") Then Set conn_"&md5&" = "& o_ds("conn") &" Else Set conn_"&md5&" = App.Dao.db.Conn ", "Set conn_"&md5&" = App.Dao.db.Conn ") & VBCrlf &" " &_
						AB.C.IIF(hasData, " If AB.C.IsRs("& o_ds("data") &") Then Set "&var&" = "& o_ds("data") &" ", " Set "&var&" = AB.C.NewRs() : "&var&".Open """&sql&""",conn_"&md5&",1,3 ") & VBCrlf &" " &_
						" Set "&var&" = App.Dao.LimitRs("&var&", """& o_pager("offset") &""", """& o_pager("rows") &""") "& VBCrlf &" " &_
						" If Not AB.C.IsNul("&var&") Then "& VBCrlf &" " &_
						" 	"&var&".AbsolutePosition = "&var&".AbsolutePosition + ((Abs("& o_pager("no") &")-1) * "& o_pager("size") &") "& VBCrlf &" " &_
						" 	If "&var&".Eof Then "& VBCrlf &" " &_
						" 		PageCount_"&md5&" = Abs(Int(-(App.Dao.RsCount("&var&") / "& o_pager("size") &"))) "& VBCrlf &" " &_
						" 		"&var&".AbsolutePosition = (PageCount_"&md5&"-1) * "& o_pager("size") &" + 1 "& VBCrlf &" " &_
						" 	End If "& VBCrlf &" " &_
						" 	For i_"&md5&"=0 to ("& o_pager("size") &"-1) "& VBCrlf &" " &_
						" 	If "&var&".Eof Then Exit For "& VBCrlf &" " &_
						" %"&">" &_
						"" & CmsInStr(inner,mark,var) & "" &_
						"<"&"% "&var&".MoveNext "& VBCrlf &" 	Next "& VBCrlf &" End If "& VBCrlf &" " &_
						" %"&">" )
			Else '无分页
				str = AB.C.RP( str, Match.Value, "<"&"% AB.C.Dim("""& var &""") : AB.C.Dim(""conn_"& md5 &""") "& VBCrlf &" " &_
				AB.C.IIF(hasConn, " If AB.C.IsConn("& o_ds("conn") &") Then Set conn_"&md5&" = "& o_ds("conn") &" Else Set conn_"&md5&" = App.Dao.db.Conn ", "Set conn_"&md5&" = App.Dao.db.Conn ") & VBCrlf &" " &_
				AB.C.IIF(hasData, " If AB.C.IsRs("& o_ds("data") &") Then Set "&var&" = "& o_ds("data") &" ", " Set "&var&" = AB.C.NewRs() : "&var&".Open """&sql&""",conn_"&md5&",1,3 ") & VBCrlf &" " &_
				" Set "&var&" = App.Dao.LimitRs("&var&", """& o_pager("offset") &""", """& o_pager("rows") &""") "& VBCrlf &" " &_
				" Do While Not "&var&".Eof %"&">" &_
				"" & CmsInStr(inner,mark,var) &"<"&"% "&var&".MoveNext : Loop %"&">" )
			End If
			If AB.C.RegTest(str, rule) Then
				str = Me.ParseCmsTag(str) '递归解析同类标签
			End If
		Next
		Set RegAttrs = Nothing
		Set RegEx = Nothing
		'-- 分页标签：{pagetag:pager data='' sql='' size='10' mark='p'} .. {/pagetag:pager}
		rule = "{pagetag:([a-z0-9_\-]+)\s*([\s\S]*?)}([\s\S]*?){/pagetag:\1}" '通用分页标签
		Set RegEx = AB.C.RegMatch(str, rule)
		For Each Match In RegEx
			o_ds.RemoveAll
			mark = Match.SubMatches(0)
			attrs = Match.SubMatches(1) '各项属性
			inner = Match.SubMatches(2)
			tmp = "" : sql = "" : table="" : where=""
			Set RegAttrs = AB.C.RegMatch(attrs, "([a-zA-Z0-9_]+)\s*=\s*(['""]?)([^'""\s]*|[^\2]*?)\2")
			For Each attr In RegAttrs
				cvar = Trim(attr.SubMatches(0))
				cval = attr.SubMatches(2)
				Select Case LCase(cvar)
					Case "sql"
						tmp = Trim(cval)
						If LCase(cvar)="sql" Then tmp = AB.C.RP(tmp, "#@", prefix) '替换数据表前缀
						tmp = AB.C.RP( tmp, "\\", Chr(24) ) '替换普通\符号
						tmp = AB.C.RP( tmp, "\$", Chr(25) ) '替换普通$符号
						tmp = AB.C.RegReplace( tmp, "\(\$([\w]+)\)", """& $1 &""" ) '替换变量
						tmp = AB.C.RegReplace( tmp, "<"&"%=(.+)%"&">", """& $1 &""" ) '替换变量
						tmp = AB.C.RP( tmp, Chr(25), "$" ) '替换普通$符号
						tmp = AB.C.RP( tmp, Chr(24), "\" ) '替换普通\符号
						o_ds("sql") = Trim(tmp)
					Case Else 'e.g. data
						o_ds(LCase(cvar)) = cval
				End Select
			Next
			tmp = ""
			If Trim(o_ds("count"))<>"" Then
				tmp = CLng(o_ds("count"))
			ElseIf o_ds("data")<>"" Then
				tmp = o_ds("data")
			ElseIf o_ds("sql")<>"" Then
				tmp = Trim(o_ds("sql"))
				o_pager("sql") = tmp
			Else
				'If hasPageSize And o_pager("set")<>"" Then tmp = o_pager("set")
				If o_pager("set")<>"" Then tmp = o_pager("set")
			End If
			If Trim(o_ds("mark"))<>"" Then o_pager("mark") = o_ds("mark")
			If Trim(o_ds("size"))<>"" Then o_pager("size") = o_ds("size")
			If Trim(o_ds("offset"))<>"" Then o_pager("offset") = o_ds("offset") '偏移量
			If Trim(o_ds("rows"))<>"" Then o_pager("rows") = o_ds("rows") '取数量
			o_pager("mark") = AB.C.IfHas(Trim(o_pager("mark")), "p") '分页标识符
			o_pager("size") = AB.C.IfHas(o_pager("size"), CLng(App.View.PageSize)) '每页数量
			o_pager("no") = CLng(App.Req( o_pager("mark") )) '当前页码
			If o_pager("no")<=0 Then o_pager("no") = 1
			md5 = LCase(AB.E.Md5.To8(Now()& AB.C.Rand(10000,99999)))
			var = mark & "_" & md5
			If Trim(o_ds("return"))<>"" Then var = Trim(o_ds("return")) '用return值作标识符
			str = AB.C.RP( str, Match.Value, "<"&"% Dim "&var&" : Set "&var&" = App.View.TagCom.PageData( """& tmp &""", """& o_pager("no") &""", """& o_pager("size") &""", """& o_pager("mark") &""", """& o_pager("offset") &""", """& o_pager("rows") &""" ) %"&">" &_
				"" & PagerInStr(inner,mark,var) &"<"&"% Set "&var&" = Nothing %"&">" )
		Next
		Set RegAttrs = Nothing
		Set RegEx = Nothing
		If AB.C.RegTest(str, rule_asp) Then '用于嵌套
			Set RegExTmp = AB.C.RegMatch(str, rule_asp)
			For Each MatchTmp In RegExTmp
				tmp = MatchTmp.SubMatches(0)
				tmp = AB.C.RP( tmp, Array(Chr(15),Chr(16)), Array("'","""") )
				str = AB.C.RP( str, MatchTmp.Value, "<"&"%="& tmp &"%"&">")
			Next
		End If
		Set RegExTmp = Nothing
		ParseCmsTag = str
		On Error GoTo 0
	End Function

	Public Function ParseSysTag(ByVal str)
		On Error Resume Next
		'str = str
		ParseSysTag = str
		On Error GoTo 0
	End Function

	Private Function CmsInStr(ByVal str, ByVal mark, ByVal var)
		On Error Resume Next
		Dim RegEx, Match, rule, rulex, field, extra, data
		Dim RegAttrs, attr, cvar, cval, sfun, tmp
		rulex = "\["& mark &":(\#)\]([\s\S]*?)\[/"& mark &":\1\]"
		Set RegEx = AB.C.RegMatch(str, rulex)
		For Each Match In RegEx
			data = Match.SubMatches(1)
			data = AB.C.RegReplace( data, "(['""])([^\1]*?)\1", """$2""" )
			data = AB.C.RP( data, Array("\\","\~"), Array(Chr(14),Chr(15)) )
			data = AB.C.RegReplace( data, "~(\w+)~", ""&var&"(""$1"")" )
			data = AB.C.RP( data, Array(Chr(15),Chr(14)), Array("~","\") )
			str = AB.C.RP( str, Match.Value, "<"&"% "& data &" %"&">" )
		Next
		Set RegAttrs = Nothing
		Set RegEx = Nothing
		rule = "\["& mark &":([a-z0-9_]+)([^]]*?)\]"
		Set RegEx = AB.C.RegMatch(str, rule)
		For Each Match In RegEx
			field = Match.SubMatches(0)
			extra = Match.SubMatches(1)
			sfun = ""
			Set RegAttrs = AB.C.RegMatch(extra,"([a-zA-Z0-9_]+)=(['""]?)([^'""\s]*|[^\2]*?)\2")
			For Each attr In RegAttrs
				cvar = Trim(attr.SubMatches(0))
				cval = attr.SubMatches(2)
				Select Case LCase(cvar)
					Case "len" '截取字符串,例：len=8
						sfun = "AB.C.CutStr(@%LJX%@, """& cval &":"")"
					Case "md5" '进行md5加密,例：md5=16
						cval = Trim(cval)
						If Not ( cval="16" Or cval="32" Or cval="8" ) Then cval="32"
						sfun = "AB.E.Md5.MD5(@%LJX%@, "&cval&")"
					Case "empty" '设置为空默认值,例：empty='0'
						cval = cval
						sfun = "AB.C.IfHas(@%LJX%@, """& cval &""")"
					Case "fun" '自定义函数,例：fun='len(@me)'
						cval = AB.C.RegReplace( cval, "(['""])([^\1]*?)\1", """$2""" )
						sfun = cval
				End Select
			Next
			If Trim(sfun)="" Then
				str = AB.C.RP( str, Match.Value, "<"&"%="&var&"("""&field&""")%"&">" )
			Else
				sfun = AB.C.RP( sfun, "@me", ""&var&"("""&field&""")" )
				str = AB.C.RP( str, Match.Value, "<"&"%="& AB.C.RP(sfun, "@%LJX%@", ""&var&"("""&field&""")") & "%"&">" )
			End If
		Next
		Set RegAttrs = Nothing
		Set RegEx = Nothing
		CmsInStr = str
		On Error GoTo 0
	End Function

	Private Function PagerInStr(ByVal str, ByVal mark, ByVal var)
		On Error Resume Next
		Dim RegEx, Match, rule, field, extra
		rule = "\["& mark &":([a-z0-9_]+)([^]]*?)\]"
		Set RegEx = AB.C.RegMatch(str, rule)
		For Each Match In RegEx
			field = Match.SubMatches(0)
			extra = Match.SubMatches(1)
			str = AB.C.RP( str, Match.Value, "<"&"%="&var&"("""&field&""")%"&">" )
		Next
		Set RegEx = Nothing
		PagerInStr = str
		On Error GoTo 0
	End Function
	
End Class
%>